package com.devilvan.betrice.opgg.controller;

import com.alibaba.fastjson.JSONObject;
import com.devilvan.betrice.common.BetriceResultCode;
import com.devilvan.betrice.common.BetriceResultVo;
import com.devilvan.betrice.opgg.dto.*;
import com.devilvan.betrice.opgg.po.OpggHeaderPo;
import com.devilvan.betrice.opgg.service.*;
import com.devilvan.betrice.opgg.vo.*;
import com.devilvan.betrice.util.UString;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
 * @author Evad.Wu
 * @Description OPGG-基本信息 控制器
 * @date 2022-10-04
 */
@RestController
@RequestMapping(value = "opggController")
@Tag(name = "OPGG-基本信息 控制器")
public class OpggController {
    @Resource(name = "opggHeaderServiceImpl")
    private OpggHeaderService opggHeaderService;
    @Resource(name = "opggChampionMetaServiceImpl")
    private OpggChampionMetaService opggChampionMetaService;
    @Resource(name = "opggChampionPositionServiceImpl")
    private OpggChampionPositionService opggChampionPositionService;
    @Resource(name = "opggChampionRoleServiceImpl")
    private OpggChampionRoleService opggChampionRoleService;
    @Resource(name = "opggLegendServiceImpl")
    private OpggLegendService opggLegendService;
    @Resource(name = "opggPositionCounterServiceImpl")
    private OpggPositionCounterService opggPositionCounterService;
    @Resource(name = "opggPositionRoleServiceImpl")
    private OpggPositionRoleService opggPositionRoleService;

    /**
     * 总请求控制器
     *
     * @return 形式返回
     */
    @Operation(summary = "总请求控制器")
    @GetMapping(value = "doOpggHeader")
    public BetriceResultVo<OpggHeaderPo> doOpggHeader() {
        BetriceResultVo<OpggHeaderPo> betriceResultVo = new BetriceResultVo<>();
        return betriceResultVo;
    }

    /**
     * 采集报文控制器
     *
     * @return 形式返回
     */
    @Operation(summary = "采集报文控制器")
    @GetMapping(value = "doOpggHeaderCrawler")
    public BetriceResultVo<OpggHeaderPo> doOpggHeaderCrawler() {
        BetriceResultVo<OpggHeaderPo> betriceResultVo = new BetriceResultVo<>();
        return betriceResultVo;
    }

    /**
     * 解析报文控制器
     *
     * @param request 报文
     * @return 形式返回
     */
    @Operation(summary = "解析报文控制器")
    @GetMapping(value = "doOpggHeaderRequest")
    public BetriceResultVo<OpggHeaderPo> doOpggHeaderRequest(@RequestBody String request) {
        BetriceResultVo<OpggHeaderPo> betriceResultVo = new BetriceResultVo<>();
        try {
            JSONObject pageProps = JSONObject.parseObject(request).getJSONObject("pageProps");
            OpggHeaderVo opggHeaderVo = pageProps.toJavaObject(OpggHeaderVo.class);
            // OpggHeaderDto
            OpggHeaderDto opggHeaderDto = this.parseCopyHeaderDto(opggHeaderVo);
            OpggHeaderPo opggHeaderPo = opggHeaderService.saveUpdate(opggHeaderDto);
            Long saveHeaderId = opggHeaderPo.getId();
            // OpggChampionMetaDto
            List<OpggChampionMetaVo> championMetaVoList = opggHeaderVo.getChampionMetaVoList();
            List<OpggChampionMetaDto> opggChampionMetaDtoList = this.parseCopyChampionMetaDto(championMetaVoList, saveHeaderId);
            List<OpggChampionPositionDto> opggChampionPositionDtoList = new ArrayList<>();
            List<OpggPositionRoleDto> opggPositionRoleDtoList = new ArrayList<>();
            List<OpggPositionCounterDto> opggPositionCounterDtoList = new ArrayList<>();
            List<OpggChampionRoleDto> opggChampionRoleDtoList = new ArrayList<>();
            for (OpggChampionMetaVo opggChampionMetaVo : championMetaVoList) {
                Long championId = opggChampionMetaVo.getChampionId();
                // OpggChampionPositionDto
                List<OpggChampionPositionVo> opggChampionPositionVoList = opggChampionMetaVo.getOpggChampionPositionVoList();
                List<OpggChampionPositionDto> parseCopyChampionPositionDto = this.parseCopyChampionPositionDto(
                        opggChampionPositionVoList, saveHeaderId, championId, opggChampionMetaVo.getName(), UString.upperCaseFirst(opggChampionMetaVo.getKeyName()));
                opggChampionPositionDtoList.addAll(parseCopyChampionPositionDto);
                // OpggPositionRoleDto
                List<OpggPositionRoleDto> parseCopyPositionRoleDtoList = this.parseCopyPositionRoleDto(opggChampionPositionVoList, saveHeaderId, championId);
                opggPositionRoleDtoList.addAll(parseCopyPositionRoleDtoList);
                // OpggPositionCounterDto
                List<OpggPositionCounterDto> parseCopyPositionCounterDtoList = this.parseCopyPositionCounterDto(opggChampionPositionVoList, saveHeaderId, championId);
                opggPositionCounterDtoList.addAll(parseCopyPositionCounterDtoList);
                // OpggChampionRoleDto
                List<OpggChampionRoleVo> opggChampionRoleVoList = opggChampionMetaVo.getOpggChampionRoleVoList();
                List<OpggChampionRoleDto> parseCopyChampionRoleDtoList = this.parseCopyChampionRoleDto(opggChampionRoleVoList, saveHeaderId, championId);
                opggChampionRoleDtoList.addAll(parseCopyChampionRoleDtoList);
            }
            // OpggLegendDto
            List<OpggLegendDto> opggLegendDtoList = championMetaVoList.stream().map(this::parseCopyLegendDto).toList();
            opggChampionMetaService.saveUpdateBatch(opggChampionMetaDtoList);
            opggChampionPositionService.saveUpdateBatch(opggChampionPositionDtoList);
            opggPositionRoleService.saveUpdateBatch(opggPositionRoleDtoList);
            opggPositionCounterService.saveUpdateBatch(opggPositionCounterDtoList);
            opggChampionRoleService.saveUpdateBatch(opggChampionRoleDtoList);
            opggLegendService.checkSaveBatch(opggLegendDtoList);
            betriceResultVo.result(BetriceResultCode.SUCCESS_200, "操作成功！");
        } catch (Exception e) {
            e.printStackTrace();
            betriceResultVo.result(BetriceResultCode.FAILED_500, "操作失败：" + e);
        }
        return betriceResultVo;
    }

    /**
     * 解析vo并赋值给dto
     *
     * @param opggChampionMetaVo vo
     * @return dto
     */
    private OpggLegendDto parseCopyLegendDto(OpggChampionMetaVo opggChampionMetaVo) {
        OpggLegendDto opggLegendDto = new OpggLegendDto();
        opggLegendDto.setChampionId(opggChampionMetaVo.getChampionId());
        opggLegendDto.setName(opggChampionMetaVo.getName());
        opggLegendDto.setKeyName(UString.upperCaseFirst(opggChampionMetaVo.getKeyName()));
        opggLegendDto.setKeyCn(opggChampionMetaVo.getName());
        opggLegendDto.setImgUrl(opggChampionMetaVo.getImgUrl());
        return opggLegendDto;
    }

    /**
     * 解析vo并赋值给dto
     *
     * @param opggChampionRoleVoList vo集合
     * @param headerId               header保存后的ID
     * @param championId             英雄ID
     * @return dto集合
     */
    private List<OpggChampionRoleDto> parseCopyChampionRoleDto(List<OpggChampionRoleVo> opggChampionRoleVoList, Long headerId, Long championId) {
        List<OpggChampionRoleDto> opggChampionRoleDtoList = new ArrayList<>();
        for (OpggChampionRoleVo opggChampionRoleVo : opggChampionRoleVoList) {
            OpggChampionRoleDto opggChampionRoleDto = new OpggChampionRoleDto();
            opggChampionRoleDto.setHid(headerId);
            opggChampionRoleDto.setChampionId(championId);
            opggChampionRoleDto.setRole(opggChampionRoleVo.getRole());
            OpggRoleStatVo opggRoleStatVo = opggChampionRoleVo.getOpggRoleStatVo();
            opggChampionRoleDto.setWinRate(opggRoleStatVo.getWinRate());
            opggChampionRoleDto.setRoleRate(opggRoleStatVo.getRoleRate());
            opggChampionRoleDto.setPlay(opggRoleStatVo.getPlay());
            opggChampionRoleDto.setWin(opggRoleStatVo.getWin());
            opggChampionRoleDtoList.add(opggChampionRoleDto);
        }
        return opggChampionRoleDtoList;
    }

    /**
     * 解析vo并赋值给dto
     *
     * @param opggChampionPositionVoList vo集合
     * @param headerId                   header保存后的ID
     * @param championId                 英雄ID
     * @return dto集合
     */
    private List<OpggPositionCounterDto> parseCopyPositionCounterDto(List<OpggChampionPositionVo> opggChampionPositionVoList, Long headerId, Long championId) {
        List<OpggPositionCounterDto> opggPositionCounterDtoList = new ArrayList<>();
        for (OpggChampionPositionVo opggChampionPositionVo : opggChampionPositionVoList) {
            List<OpggPositionCounterVo> opggPositionCounterVoList =
                    Optional.ofNullable(opggChampionPositionVo.getOpggPositionCounterVoList()).orElseGet(ArrayList::new);
            for (OpggPositionCounterVo opggPositionCounterVo : opggPositionCounterVoList) {
                OpggPositionCounterDto opggPositionCounterDto = new OpggPositionCounterDto();
                opggPositionCounterDto.setHid(headerId);
                opggPositionCounterDto.setChampionId(championId);
                Integer counterWin = opggPositionCounterVo.getWin();
                Integer counterPlay = opggPositionCounterVo.getPlay();
                opggPositionCounterDto.setWin(counterWin);
                opggPositionCounterDto.setPlay(counterPlay);
                double win = Optional.ofNullable(counterWin).map(m -> (double) m).orElse(0d);
                double play = Optional.ofNullable(counterPlay).map(m -> (double) m).orElse(0d);
                if (win >= 0 && play > 0) {
                    BigDecimal winRate = BigDecimal.valueOf(win / play).setScale(6, RoundingMode.CEILING);
                    opggPositionCounterDto.setWinRate(winRate);
                }
                opggPositionCounterDtoList.add(opggPositionCounterDto);
            }
        }
        return opggPositionCounterDtoList;
    }

    /**
     * 解析vo并赋值给dto
     *
     * @param opggChampionPositionVoList vo集合
     * @param headerId                   header保存后的ID
     * @param championId                 英雄ID
     * @return dto集合
     */
    private List<OpggPositionRoleDto> parseCopyPositionRoleDto(List<OpggChampionPositionVo> opggChampionPositionVoList, Long headerId, Long championId) {
        List<OpggPositionRoleDto> opggPositionRoleDtoList = new ArrayList<>();
        for (OpggChampionPositionVo opggChampionPositionVo : opggChampionPositionVoList) {
            List<OpggPositionRoleVo> opggPositionRoleVoList =
                    Optional.ofNullable(opggChampionPositionVo.getOpggPositionRoleVoList()).orElseGet(ArrayList::new);
            for (OpggPositionRoleVo opggPositionRoleVo : opggPositionRoleVoList) {
                OpggPositionRoleDto opggPositionRoleDto = new OpggPositionRoleDto();
                opggPositionRoleDto.setHid(headerId);
                opggPositionRoleDto.setChampionId(championId);
                opggPositionRoleDto.setRole(opggPositionRoleVo.getRole());
                OpggRoleStatVo opggRoleStatVo = opggPositionRoleVo.getOpggRoleStatVo();
                if (Optional.ofNullable(opggRoleStatVo).isPresent()) {
                    opggPositionRoleDto.setWinRate(opggRoleStatVo.getWinRate());
                    opggPositionRoleDto.setRoleRate(opggRoleStatVo.getRoleRate());
                    opggPositionRoleDto.setPlay(opggRoleStatVo.getPlay());
                    opggPositionRoleDto.setWin(opggRoleStatVo.getWin());
                    opggPositionRoleDtoList.add(opggPositionRoleDto);
                }
            }
        }
        return opggPositionRoleDtoList;
    }

    /**
     * 解析vo并赋值给dto
     *
     * @param opggChampionPositionVoList vo集合
     * @param headerId                   header保存后的ID
     * @param championId                 英雄ID
     * @param name                       英雄称号
     * @param key                        英雄名称
     * @return dto集合
     */
    private List<OpggChampionPositionDto> parseCopyChampionPositionDto(
            List<OpggChampionPositionVo> opggChampionPositionVoList, Long headerId, Long championId, String name, String key) {
        List<OpggChampionPositionDto> championPositionDtoList = new ArrayList<>();
        for (OpggChampionPositionVo opggChampionPositionVo : opggChampionPositionVoList) {
            OpggChampionPositionDto opggChampionPositionDto = new OpggChampionPositionDto();
            opggChampionPositionDto.setHid(headerId);
            opggChampionPositionDto.setChampionId(championId);
            opggChampionPositionDto.setName(name);
            opggChampionPositionDto.setKeyName(key);
            opggChampionPositionDto.setPosition(opggChampionPositionVo.getName());

            OpggPositionStatVo opggPositionStatVo =
                    Optional.ofNullable(opggChampionPositionVo.getOpggPositionStatVo()).orElseGet(OpggPositionStatVo::new);
            opggChampionPositionDto.setWinRate(opggPositionStatVo.getWinRate());
            opggChampionPositionDto.setPickRate(opggPositionStatVo.getPickRate());
            opggChampionPositionDto.setRoleRate(opggPositionStatVo.getRoleRate());
            opggChampionPositionDto.setBanRate(opggPositionStatVo.getBanRate());
            opggChampionPositionDto.setKda(opggPositionStatVo.getKda());

            OpggPositionStatTierVo opggPositionStatTierVo = opggPositionStatVo.getOpggPositionStatTierVo();
            if (Optional.ofNullable(opggPositionStatTierVo).isPresent()) {
                opggChampionPositionDto.setTier(opggPositionStatTierVo.getTier());
                opggChampionPositionDto.setPositionRank(opggPositionStatTierVo.getRank());
                opggChampionPositionDto.setRankPrev(opggPositionStatTierVo.getRankPrev());
                opggChampionPositionDto.setRandPrevPatch(opggPositionStatTierVo.getRandPrevPatch());
                championPositionDtoList.add(opggChampionPositionDto);
            }
        }
        return championPositionDtoList;
    }

    /**
     * 解析vo并赋值给dto
     *
     * @param championMetaVoList vo集合
     * @param headerId           header保存后的ID
     * @return dto集合
     */
    private List<OpggChampionMetaDto> parseCopyChampionMetaDto(List<OpggChampionMetaVo> championMetaVoList, Long headerId) {
        List<OpggChampionMetaDto> championMetaDtoList = new ArrayList<>();
        for (OpggChampionMetaVo opggChampionMetaVo : championMetaVoList) {
            OpggChampionMetaDto opggChampionMetaDto = new OpggChampionMetaDto();
            opggChampionMetaDto.setHid(headerId);
            opggChampionMetaDto.setChampionId(opggChampionMetaVo.getChampionId());
            opggChampionMetaDto.setName(opggChampionMetaVo.getName());
            opggChampionMetaDto.setKeyName(UString.upperCaseFirst(opggChampionMetaVo.getKeyName()));
            opggChampionMetaDto.setImgUrl(opggChampionMetaVo.getImgUrl());

            OpggChampionMetaAvgStatVo opggChampionMetaAvgStatVo = opggChampionMetaVo.getOpggChampionMetaAvgStatVo();
            if (Optional.ofNullable(opggChampionMetaAvgStatVo).isPresent()) {
                opggChampionMetaDto.setAvgWinRate(opggChampionMetaAvgStatVo.getAvgWinRate());
                opggChampionMetaDto.setAvgPickRate(opggChampionMetaAvgStatVo.getAvgPickRate());
                opggChampionMetaDto.setAvgBanRate(opggChampionMetaAvgStatVo.getAvgBanRate());
                opggChampionMetaDto.setAvgKda(opggChampionMetaAvgStatVo.getAvgKda());
                opggChampionMetaDto.setAvgTier(opggChampionMetaAvgStatVo.getAvgTier());
                opggChampionMetaDto.setAvgRank(opggChampionMetaAvgStatVo.getAvgRank());
            }
            championMetaDtoList.add(opggChampionMetaDto);
        }
        return championMetaDtoList;
    }

    /**
     * 解析vo并赋值给dto
     *
     * @param opggHeaderVo vo
     * @return dto
     */
    private OpggHeaderDto parseCopyHeaderDto(OpggHeaderVo opggHeaderVo) {
        OpggHeaderDto opggHeaderDto = new OpggHeaderDto();
        opggHeaderDto.setAcDate(new Date());
        opggHeaderDto.setPosition(opggHeaderVo.getPosition());
        opggHeaderDto.setRegion(opggHeaderVo.getRegion());
        opggHeaderDto.setTier(opggHeaderVo.getTier());
        OpggVersionDataVo versionData = opggHeaderVo.getVersionData();
        if (Optional.ofNullable(versionData).isPresent()) {
            opggHeaderDto.setVersion(versionData.getVersion());
        }
        return opggHeaderDto;
    }
}
